/* Copyright (c) 2004-2008, Andriy Nikolov
 * All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.processmining.analysis.email;

import org.processmining.email.*;
import javax.swing.*;
import org.processmining.framework.plugin.*;
import org.processmining.analysis.*;
import org.processmining.framework.ui.*;
import java.awt.*;
import org.processmining.framework.util.*;
import att.grappa.*;
import java.text.*;
import java.io.*;

/**
 * <p>An analysis plugin, which produces a user-case diagram from the process
 * log mined from an e-mail log. Takes as an input a ProvidedObject instance,
 * which contains a ProcessLog instance.
 *
 * @author Andriy Nikolov
 * @version 1.0
 */
public class EMailProcessLogUserCaseDiagramAnalysis extends JPanel implements AnalysisPlugin {
  CasePersonTable casePersonTable;
  ProcessLog log;
  BorderLayout borderLayout1 = new BorderLayout();
  GrappaPanel grappaPanel;
  JScrollPane scrollPane = new JScrollPane();

  public EMailProcessLogUserCaseDiagramAnalysis() {
    try {
      jbInit();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public String getHtmlDescription() {
      return "...";
  }

  public String getName() {
    return ("User - Case Diagram");
  }

  /**
   * accepts only input items containing ProcessLog instances
   *
   * @return AnalysisInputItem[]
   */
  public AnalysisInputItem[] getInputItems() {
    AnalysisInputItem[] items = {
      new AnalysisInputItem("E-mail log") {
        public boolean accepts(ProvidedObject object) {
          Object[] o = object.getObjects();
          for(int i=0;i<o.length;i++)
            if(o[i] instanceof ProcessLog)
              return true;
          return false;
        }
      }
    } ;
    return items;
  }

  /**
   * Produces a user-case diagram based on the process log mined from an e-mail
   *
   * @param inputs AnalysisInputItem[]
   * @return JPanel
   */
  public JComponent analyse(AnalysisInputItem[] inputs) {
     log = null;
     AnalysisInputItem inputItem;
     ProvidedObject[] pos;
     ProvidedObject po;
     Object[] os;
     Object o;

     inputItem = inputs[0];
     pos = inputItem.getProvidedObjects();
     po = pos[0];
     os = po.getObjects();

     for(int i=0;i<os.length;i++) {
       o = os[i];
       if(o instanceof ProcessLog) {
         log = (ProcessLog)o;
         break;
       }
     }

     if(log==null)
       return null;
     casePersonTable = log.getCasePersonTable();

     drawGraphPanel();
     scrollPane.getViewport().add(grappaPanel);

     return this;
  }

  public void jbInit() {
    this.setLayout(borderLayout1);
    this.add(scrollPane, BorderLayout.CENTER);
  }

  private void drawGraphPanel() {
    BufferedWriter bw;
    Graph graph;
    NumberFormat nf = NumberFormat.getInstance();
    File dotFile;

    ProcessCase tmp;
    int numPeople, numCases;

    nf.setMinimumFractionDigits(3);
    nf.setMaximumFractionDigits(3);
    try {
      // create temporary DOT file
      dotFile = File.createTempFile("pmt", ".dot");
      bw = new BufferedWriter(new FileWriter(dotFile, false));
      bw.write("digraph G {ranksep=\".3\"; fontsize=\"8\"; remincross=true; margin=\"0.0,0.0\"; ");
      bw.write("fontname=\"Arial\";rankdir=\"LR\"; \n");
      bw.write("edge [arrowsize=\"0.5\",decorate=true,fontname=\"Arial\",fontsize=\"8\"];\n");
      bw.write("node [height=\".1\",width=\".2\",fontname=\"Arial\",fontsize=\"8\"];\n");

      numPeople = casePersonTable.getPersonList().size();
      numCases = casePersonTable.getCaseList().size();

      for (int i = 0; i < numPeople; i++) {
        if(casePersonTable.isPersonConnected((String) casePersonTable.getPersonList().get(i))) {
          bw.write("t" + i + " [shape=\"box\",label=\"" +
                   (String) casePersonTable.getPersonList().get(i) + "\"];\n");
        }
      }

      for(int i = 0; i < numCases; i++) {
        bw.write("t" + (i+numPeople) + " [shape=\"box\",label=\"" + (String)casePersonTable.getCaseList().get(i) + "\"];\n");
      }

      for (int i = 0; i < numPeople; i++) {
        for (int j = 0; j < numCases; j++) {
          double value = casePersonTable.getNormalizedWeight((String)casePersonTable.getCaseList().get(j), (String) casePersonTable.getPersonList().get(i));

          if (value > 0) {
            bw.write("t" + i + " -> t" + (j+numPeople) + " [label=\"" + nf.format(value) + "\"];\n");
          }
        }
      }
      bw.write("}\n");
      bw.close();

      // execute dot and parse the output of dot to create a Graph
      System.out.println(dotFile.getAbsolutePath());
      graph = Dot.execute(dotFile.getAbsolutePath(), true);

      // adjust some settings
      graph.setEditable(true);
      graph.setMenuable(true);
      graph.setErrorWriter(new PrintWriter(System.err, true));

      // create the visual component and return it
      grappaPanel = new GrappaPanel(graph);
      grappaPanel.addGrappaListener(new GrappaAdapter());
      grappaPanel.setScaleToFit(true);

    } catch (Exception ex) {
      Message.add("Error while performing graph layout: " + ex.getMessage(), Message.ERROR);
      ex.printStackTrace();
      return;
    }
  }

}
